import java.util.Arrays;

/**
 * 给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数，使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
 * <p>
 *  
 * <p>
 * 示例：
 * <p>
 * 输入：nums = [-1,2,1,-4], target = 1
 * 输出：2
 * 解释：与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
 */
class Solution {

    public static void main(String[] args) {
        System.out.println(threeSumClosest(new int[]{-1, 2, 1, 4, 5, 6}, 1));
        // System.out.println(threeSumClosest(new int[]{0, 2, 1, -3}, 1));
    }

    /**
     * 最原始的方法, 遍历cmn种情况
     *
     * @param nums
     * @param target
     * @return
     */
    public static int threeSumClosest1(int[] nums, int target) {
        int res = nums[0] + nums[1] + nums[2];
        int min = Math.abs(res - target);
        int tmp, tmpMin, tmpRes;
        for (int i = 0; i < nums.length - 2; i++) {
            for (int j = i + 1; j < nums.length - 1; j++) {
                tmp = nums[i] + nums[j];
                for (int k = j + 1; k < nums.length; k++) {
                    tmpRes = tmp + nums[k];
                    tmpMin = Math.abs(tmpRes - target);
                    if (tmpMin < min) {
                        min = tmpMin;
                        res = tmpRes;
                    }
                }
            }
        }
        return res;
    }

    /**
     * 在排序完成后，某一个点固定后，另外的两个点肯定可以用双指针遍历到，可以把n3的复杂度变成n2
     *
     * @param nums
     * @param target
     * @return
     */
    public static int threeSumClosest(int[] nums, int target) {
        // 先排序
        Arrays.sort(nums);
        int res = nums[0] + nums[1] + nums[2];
        int min = Math.abs(res - target);
        int tmpRes;
        int tmpMin;
        // 再计算,可以排除很多情况
        for (int i = 0; i < nums.length - 2; i++) {
            // 使用双指针，只需要再遍历一次
            for (int start = i + 1, end = nums.length - 1; start < end; ) {
                tmpRes = nums[i] + nums[start] + nums[end];
                tmpMin = Math.abs(tmpRes - target);
                if (tmpMin < min) {
                    // 如果小于最小值，则赋值
                    // 如果为0则返回
                    if (tmpMin == 0) {
                        return tmpRes;
                    }
                    min = tmpMin;
                    res = tmpRes;
                }
                // 根据结果判断反向
                if (tmpRes < target) {
                    start++;
                } else {
                    end--;
                }
            }
        }
        return res;
    }

}